﻿using Newtonsoft.Json;
using SuperWebSocket;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace ByteSite.Common
{
    public class WebSocketManager
    {

        private TransferSocket tSocket = new TransferSocket(); // 套接字 规则
        private TransferFilesSeting tRules = new TransferFilesSeting(); // 文件传输 规则

        /// <summary>
        /// 远程协助包合集
        /// </summary>
        private static List<WebSocketMessage> remoteDesktopPackets = new List<WebSocketMessage>();

        //static Dictionary<string, WebSocketSession> sessionDics = new Dictionary<string, WebSocketSession>();
        private static List<ClientInfo> clientList = new List<ClientInfo>();

        static WebSocketServer webSocketServer;
        public static void Init()
        {
            var ip = GetLocalIP();
            webSocketServer = new WebSocketServer();
            bool isSetup = webSocketServer.Setup(ip, 21024);
            if (isSetup)
                LoggerHelper.Info("WebSocketManager：服务器端启动成功" + " " + ip + ":21024");
            else
                LoggerHelper.Error("WebSocketManager：服务器端启动失败" + " " + ip + ":21024");


            if (!isSetup)
                return;

            webSocketServer.NewSessionConnected += WebSocketServer_NewSessionConnected;
            webSocketServer.SessionClosed += WebSocketServer_SessionClosed;
            webSocketServer.NewMessageReceived += WebSocketServer_NewMessageReceived;//当有消息传入
            webSocketServer.NewDataReceived += WebSocketServer_NewDataReceived;//当有数据传入时

            bool isStart = webSocketServer.Start();
            if (isStart)
                LoggerHelper.Info("WebSocketManager：服务器端侦听成功" + " " + ip + ":21024");
            else
                LoggerHelper.Error("WebSocketManager：服务器端侦听失败" + " " + ip + ":21024");
        }
        private static void WebSocketServer_NewDataReceived(WebSocketSession session, byte[] value)
        {
            //string str = Encoding.UTF8.GetString(value);
            //LoggerHelper.Info("WebSocketManager：接收数据 \r\n" + str);

            //if (clientList.Exists(x => x.SessionId == session.SessionID && x.NetAddressInfo == (session.RemoteEndPoint.AddressFamily + "_" + session.RemoteEndPoint.Address + ":" + session.RemoteEndPoint.Port)))
            //{
            //    ClientInfo clientInfo = clientList.Find(x => x.SessionId == session.SessionID && x.NetAddressInfo == (session.RemoteEndPoint.AddressFamily + "_" + session.RemoteEndPoint.Address + ":" + session.RemoteEndPoint.Port));
            //    clientInfo.Session = session;

            //    ///将数据中转给admin用户
            //    if (value != null && value.Length > 0)
            //    {
            //        List<ClientInfo> clientInfos = clientList.FindAll(x => x.ClientType == "bytesite_admin");
            //        if (clientInfos.Count > 0)
            //        {
            //            foreach (ClientInfo adminClientInfo in clientInfos)
            //            {
            //                SendDataToRemotePoint(adminClientInfo.Session, value);
            //            }
            //        }
            //    }
            //}
        }

        /// <summary>
        /// 接收消息
        /// </summary>
        /// <param name="session"></param>
        /// <param name="value"></param>
        private static void WebSocketServer_NewMessageReceived(WebSocketSession session, string value)
        {
            LoggerHelper.Info("WebSocketManager：接收消息 \r\n" + value);

            if (!string.IsNullOrWhiteSpace(value))
            {
                if (value.ToString().Equals("**bytesite_heartbeat**"))//客户端定时发送心跳，维持链接
                {
                    //回复客户端心跳包
                    SendMsgToRemotePoint(session, "**bytesite_server_heartbeat**");
                }
                else
                {
                    WebSocketMessage msg = JsonHelper2.JSONToObject<WebSocketMessage>(value);
                    if (clientList.Exists(x => x.SessionId == session.SessionID && x.NetAddressInfo == (session.RemoteEndPoint.AddressFamily + "_" + session.RemoteEndPoint.Address + ":" + session.RemoteEndPoint.Port)))
                    {
                        if (msg != null)
                        {
                            ClientInfo clientInfo = clientList.Find(x =>
                                x.SessionId == session.SessionID && x.NetAddressInfo == (session.RemoteEndPoint.AddressFamily +
                                    "_" + session.RemoteEndPoint.Address +
                                    ":" + session.RemoteEndPoint.Port));
                            if (string.IsNullOrEmpty(clientInfo.ClientId))
                            {
                                clientInfo.ClientId = msg.From;
                                clientInfo.Session = session;
                                if (msg.Message == "update_client_type" && msg.Data == "bytesite_admin")
                                {
                                    clientInfo.ClientType = "bytesite_admin";
                                }
                            }

                            if (msg.Message== "remote_desktop_packet")
                            {
                                //把拆分包加入队列
                                remoteDesktopPackets.Add(msg);
                            }
                            else if(msg.Message== "remote_desktop_packet_over")
                            {
                                //合并拆分
                                if (msg.DataCount > 0 && !msg.Guid.IsNullOrEmpty())
                                {
                                    List<WebSocketMessage> everyRemoteDesktopPackets =
                                        remoteDesktopPackets.FindAll(x => x.Guid == msg.Guid);
                                    byte[] data = FileMerge(everyRemoteDesktopPackets);

                                    //将数据中转给admin用户
                                    if (data != null && data.Length > 0)
                                    {
                                        List<ClientInfo> clientInfos = clientList.FindAll(x => x.ClientType == "bytesite_admin");
                                        if (clientInfos.Count > 0)
                                        {
                                            foreach (ClientInfo adminClientInfo in clientInfos)
                                            {
                                                SendDataToRemotePoint(adminClientInfo.Session, data);
                                            }
                                        }
                                    }

                                }
                            }
                        }


                    }
                    SendMsgToRemotePoint(
                        session,
                        JsonHelper2.ObjectToJSON(
                            new WebSocketMessage()
                            {
                                Guid = msg.Guid,
                                From = "server",
                                To = msg.From,
                                Time = DateTime.Now,
                                Channel = "server",
                                MessageType = "sys",
                                Message = "received"
                            }
                        )
                    );
                    
                }
            }
        }

        /// <summary>
        /// 下线
        /// </summary>
        /// <param name="session"></param>
        /// <param name="value"></param>
        private static void WebSocketServer_SessionClosed(WebSocketSession session, SuperSocket.SocketBase.CloseReason value)
        {
            if(clientList.Exists(x => x.SessionId == session.SessionID && x.NetAddressInfo == (session.RemoteEndPoint.AddressFamily + "_" + session.RemoteEndPoint.Address + ":" + session.RemoteEndPoint.Port)))
            {
                ClientInfo clientInfo = clientList.Find(x =>
                    x.SessionId == session.SessionID);
                clientList.Remove(clientInfo);
            }
            LoggerHelper.Info(string.Format("WebSocketManager：{0} {1}下线", value, session.RemoteEndPoint));
        }

        /// <summary>
        /// 上线
        /// </summary>
        /// <param name="session"></param>
        private static void WebSocketServer_NewSessionConnected(WebSocketSession session)
        {
            if (!clientList.Exists(x => x.SessionId == session.SessionID && x.NetAddressInfo == (session.RemoteEndPoint.AddressFamily + "_" + session.RemoteEndPoint.Address + ":" + session.RemoteEndPoint.Port)))
            {
                ClientInfo clientInfo = new ClientInfo();
                clientInfo.ClientId = "";
                clientInfo.Session = session;
                clientInfo.SessionId = session.SessionID;
                clientInfo.NetAddressInfo = session.RemoteEndPoint.AddressFamily + "_" +
                                            session.RemoteEndPoint.Address + ":" + session.RemoteEndPoint.Port;
                clientInfo.ClientType = "";
                clientList.Add(clientInfo);
            }

            LoggerHelper.Info(string.Format("WebSocketManager：{0}上线", session.RemoteEndPoint));
        }


        #region 发送消息到客户端

        public static void SendMsgToRemotePoint(string value, string msg)
        {
            if (clientList.Exists(x => x.ClientId == value))
            {
                WebSocketSession webSocketSession = clientList.Find(x => x.ClientId == value).Session;
                if (webSocketSession != null)
                {
                    webSocketSession.Send(msg);
                }
            }
        }
        public static void SendMsgToRemotePoint(WebSocketSession webSocketSession, string msg)
        {
            if (webSocketSession != null)
            {
                webSocketSession.Send(msg);
            }
        }
        public static void SendDataToRemotePoint(string value, byte[] data)
        {
            if (clientList.Exists(x => x.ClientId == value))
            {
                WebSocketSession webSocketSession = clientList.Find(x => x.ClientId == value).Session;
                if (webSocketSession != null)
                {
                    webSocketSession.Send(data,0,data.Length);
                }
            }
        }
        public static void SendDataToRemotePoint(WebSocketSession webSocketSession, byte[] data)
        {
            if (webSocketSession != null)
            {
                webSocketSession.Send(data, 0, data.Length);
            }
        }

        #endregion

        /// <summary>
        /// 文件合并
        /// </summary>
        /// <param name="dataSplit"></param>
        /// <returns></returns>
        public static byte[] FileMerge(List<WebSocketMessage> dataSplit)
        {
            //MemoryStream ms;
            byte[] bytes = null;
            string duction = "";
            for (int i = 0; i < dataSplit.Count; i++)
            {
                duction += dataSplit[i].Data;
            }
            duction = Utils.UnzipString(duction);

            bytes = Convert.FromBase64String(duction);
            //ms = new MemoryStream(bytes);
            return bytes;
            //FileStream fs = new FileStream(filePath, FileMode.Create);
            //ms.WriteTo(fs);
            //fs.Close();
        }

        /// <summary>
        /// 文件拆分包
        /// </summary>
        /// <param name="packFlag">包标识</param>
        /// <param name="fileName">文件名</param>
        /// <param name="packSize">包大小 kb</param>
        /// <returns></returns>
        public static List<WebSocketMessage> FileSplit(string guid,string clientId, string message, byte[] data, int packSize)
        {
            List<WebSocketMessage> list = new List<WebSocketMessage>();

            string Zipstr = Utils.ZipString(Convert.ToBase64String(data)); // 压缩字符串

            int packNum = (int)Math.Ceiling(Zipstr.Length / (double)packSize); // 包总数
            string pack = null;


            for (int i = 0; i < packNum - 1; i++)
            {
                pack = Zipstr.Substring(i * packSize, packSize);
                list.Add(new WebSocketMessage()
                {
                    Guid = guid,

                    From = "server",
                    To = "client_" + clientId,
                    Time = DateTime.Now,
                    Channel = "server",
                    MessageType = "sys",
                    Message = message,
                    Data = pack,
                    DataNo = i,
                    DataCount = packNum
                });
            }
            // 最后剩余字节打一个包
            pack = Zipstr.Substring((packNum - 1) * packSize, Zipstr.Length - (packNum - 1) * packSize);
            list.Add(new WebSocketMessage()
            {
                Guid = guid,

                From = "server",
                To = "client_" + clientId,
                Time = DateTime.Now,
                Channel = "server",
                MessageType = "sys",
                Message = message,
                Data = pack,
                DataNo = packNum - 1,
                DataCount = packNum
            });
            return list;
        }


        /// <summary>
        /// 获取本地IP等信息
        /// </summary>
        /// <returns></returns>
        public static string GetLocalIP()
        {
            //本机IP地址 
            string strLocalIP = "";
            //得到计算机名 
            string strPcName = Dns.GetHostName();
            //得到本机IP地址数组 
            IPHostEntry ipEntry = Dns.GetHostEntry(strPcName);
            //遍历数组 
            foreach (var IPadd in ipEntry.AddressList)
            {
                //判断当前字符串是否为正确IP地址 
                if (IsIP(IPadd.ToString()))
                {
                    //得到本地IP地址 
                    strLocalIP = IPadd.ToString();
                    //结束循环 
                    break;
                }
            }

            //返回本地IP地址 
            return strLocalIP;
        }
        /// <summary>
        /// 判断是否为正确的IP地址
        /// </summary>
        /// <param name="strIPadd">需要判断的字符串</param>
        /// <returns>true = 是 false = 否</returns>
        private static bool IsIP(string strIPadd)
        {
            //利用正则表达式判断字符串是否符合IPv4格式
            if (Regex.IsMatch(strIPadd, "[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}"))
            {
                //根据小数点分拆字符串
                string[] ips = strIPadd.Split('.');
                if (ips.Length == 4 || ips.Length == 6)
                {
                    //如果符合IPv4规则
                    if (System.Int32.Parse(ips[0]) < 256 && System.Int32.Parse(ips[1]) < 256 & System.Int32.Parse(ips[2]) < 256 & System.Int32.Parse(ips[3]) < 256)
                        //正确
                        return true;
                    //如果不符合
                    else
                        //错误
                        return false;
                }
                else
                    //错误
                    return false;
            }
            else
                //错误
                return false;
        }
    }

    public class WebSocketMessage
    {

        /// <summary>
        /// 
        /// </summary>
        private string _guid = "";
        public string Guid { get { return _guid; } set { _guid = value; } }

        /// <summary>
        /// 来源
        /// </summary>
        private string _from = "";
        public string From { get { return _from; } set { _from = value; } }

        /// <summary>
        /// 目的
        /// </summary>
        private string _to = "";
        public string To { get { return _to; } set { _to = value; } }

        /// <summary>
        /// 时间
        /// </summary>
        [JsonConverter(typeof(TcDateTimeConverter))]
        public DateTime Time { get; set; }

        /// <summary>
        /// 渠道
        /// </summary>
        private string _channel = "";
        public string Channel { get { return _channel; } set { _channel = value; } }

        /// <summary>
        /// 消息类型
        /// </summary>
        private string _type = "";
        public string MessageType { get { return _type; } set { _type = value; } }

        /// <summary>
        /// 消息
        /// </summary>

        private string _message = "";
        public string Message { get { return _message; } set { _message = value; } }

        /// <summary>
        /// 数据包
        /// </summary>
        private string _data = "";
        public string Data { get { return _data; } set { _data = value; } }

        /// <summary>
        /// 数据包数据量
        /// </summary>
        private int _data_no = 0;
        public int DataNo { get { return _data_no; } set { _data_no = value; } }

        /// <summary>
        /// 数据包数据量
        /// </summary>
        private int _data_count = 0;
        public int DataCount { get { return _data_count; } set { _data_count = value; } }
    }

    public class ClientInfo
    {
        public string ClientId { get; set; }

        public  string SessionId { get; set; }

        public WebSocketSession Session { get; set; }

        public string NetAddressInfo { get; set; }

        public string ClientType { get; set; }
    }
}
